var db = require("./libs/db"); 
var mqtt = require('mqtt');
const kurento = require("kurento-client"); 

class TKmsManager{
    constructor(){
        this.config={
            clientId:"",
            kms:{
                kmsUrl:"wss://wss.hhdata.cn:8433/kurento" ,
                tagKey:"kmsManager"
            },
            db:{
                dbKey:'tm',
                dbInfo:{
                    host:"tjiot.hhdata.cn" ,
                    port:53306,
                    uid:"root",
                    pwd:"hhuc1115",
                    db:"telemedicine" , 
                    sqlPath:"D:/gitee/hhudev/web/apps/tm/sqls"
                }
            },
            mq:{
                url:"tcp://gmggf8g.mqtt.iot.bj.baidubce.com:1883",
                uid:"gmggf8g/peer",
                pwd:"a52bwKg22dCAuQzB",
                appTopic:"/hhmsg/notify"
            }
        };
        this.db = new db.TDBMySql();
        this.kmsClient = null;
        this.mqClient =null;
        this.kmsObjIdDict={};
        this.kmsObjCodeDict={};
        this.config.clientId = ['km',(new Date()).getTime(), parseInt(1000*Math.random())].join("");
    }
    openManager(){
        var me = this;
        return new Promise((success, faild)=>{
            try{
                me.db.apps[me.config.db.dbKey] = me.config.db.dbInfo;
                me.openMqClient(()=>{
                    return me.getClient();
                }).then(client=>{
                    return me.loadKmsObjs(client);
                }).then(()=>{
                    success();
                });
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    getClient(){
        var me = this;
        return new Promise((success, faild)=>{
            try{
                if( !me.kmsClient || me.kmsClient == null){
                    kurento(me.config.kms.kmsUrl, function(erClient , client){
                        me.kmsClient = client;
                        var handler = function(){
                            me.kmsClient.getServerManager( function(erSvr , svr){
                                if( erSvr || !svr || svr==null ){
                                    me.kmsClient = null;
                                    return;
                                }
                                else{
                                    setTimeout( handler , 60*1000);            
                                }
                            })
                        }
                        handler();
                        me.loadKmsObjs(client).then(()=>{
                            success();                        
                        });
                    });
                }
                else{
                    success( me.kmsClient);
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    loadKmsObjs(client){
        var me = this;
        return new Promise((success, faild)=>{
            try{
                var sql ="select * from v_currentKmsObj";
                me.db.query(sql , {} , function(res){
                    if (res && res!=null && res.result  && res.result!=null && res.result.length>0){
                        var freeItemIds =[]
                        var loadItem = function(){
                            if( res.result.length>0){
                                var info = res.result.shfit();
                                client.getMediaobjectById(function(erFind , obj){
                                    if( !erFind && obj && obj!=null){
                                        obj.info = info;
                                        me.kmsObjIdDict[info.kmsId] = obj;
                                        me.kmsObjCodeDict[info.code] = obj;
                                    }
                                    else{
                                        freeItemIds.push(info.objId);
                                        loadItem();
                                    }
                                });
                            }
                            else{
                                if( freeItemIds.length>0){
                                    sql ="delete from T_KmsObj where objId in (" + freeItemIds.join(",")+")";
                                    me.db.query(sql , {} , function(resFree){
                                        success();
                                    })

                                }
                                else{
                                    success();
                                }                                
                            }
                        }
                        loadItem();
                    }
                    else{
                        success();
                    }
                });
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    removeKmsObjsByClientId(clientId){
        var me = this;
        return new Promise((success, faild)=>{
            try{

                var objs = Object.values(me.kmsObjIdDict).filter(obj=>{
                    return obj.info.clientId == clientId;
                });
                if( objs.length>0){
                    var ids=[];
                    var removeItem = function(){
                        if( objs.length>0){
                            var obj = objs.shift();
                            var code = obj.info.code;
                            var kmsId = obj.info.kmsId;
                            var objId = obj.info.objId;
                            ids.push(objId);
                            if( me.kmsObjCodeDict[code]){
                                delete me.kmsObjCodeDict[code];
                            }
                            if( me.kmsObjIdDict[kmsId]){
                                delete me.kmsObjIdDict[kmsId];
                            }
                            try{
                                obj.release( function(erFree){
                                    removeItem();
                                })
                            }
                            catch(eer){
                                removeItem();
                            } 
                        }
                        else{
                            var sql ='delete from T_KmsObj where objId in(' + ids.join(',')+")";
                            me.db.query(sql , {} , function(resFree){
                                success();
                            })
                        }
                    }
                    removeItem();
                }
                else{
                    success();
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    openMqClient( ){
        var me = this;
        return new Promise((success, faild)=>{
            try{
                var options={
                    username: me.config.mq.uid ,
                    password: me.config.mq.pwd ,
                    clientId:'mo'+me.config.clientId
                };
                var client=mqtt.connect( me.config.mq.url , options );
                client.on('message', function (topic, message) {
                    var msg=JSON.parse(message.toString());        
                    try{
                        console.log(msg);
                        me.registMqMsg(msg); 
                    }
                    catch(e){
                        console.log(topic,msg);				
                    }
                }); 
                var topic = me.config.mq.appTopic+"/#";
                client.subscribe([topic]); 
                success();
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    } 
    registObj( obj , code , clientId ){
        var me = this;
        return new Promise((success, faild)=>{
            try{
                if( obj && obj!=null){
                    var ps = {
                        code:code ,
                        kmsId: obj.id ,
                        clientId: clientId
                    };
                    var sql = "insert into T_KmsObj(code , kmsId , clientId , createTm) values (:code , :kmsId , :clientId , unix_timestamp(now()))";
                    me.db.query(sql , ps , function(res){
                        if( res && res.result && res.result.insertId && res.result.insertId >0){
                            ps.objId =  res.result.insertId;
                            obj.info = ps;
                            me.kmsObjCodeDict[code] = obj;
                            me.kmsObjIdDict[kmsId] = obj;
                        }
                        success(obj);
                    })
                }
                else{
                    success(obj);
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    registObjById( kmsId , code , clientId ){
        var me = this;
        return new Promise((success, faild)=>{
            try{
                me.getClient().then(client=>{
                    client.getMediaobjectById(kmsId, function(erFind,obj){
                        me.registObj(obj, code , clientId).then(resObj=>{
                            success(resObj);
                        })
                    })
                })
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    loadPipe( code , clientId){
        var me = this; 
        return new Promise((success, faild)=>{
            try{
                if( me.kmsObjCodeDict[code]){
                    success(me.kmsObjCodeDict[code]);
                }
                else{
                    me.getClient().then(client=>{
                        client.create("MediaPipeline").then(pipe=>{
                            return me.registObj(pipe , code , clientId);
                        }).then(obj=>{
                            success(obj);
                        })
                    })
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    loadDevice( pipeCode , code , srcUrl ,  clientId){
        var me = this; 
        return new Promise((success, faild)=>{
            try{
                if( me.kmsObjCodeDict[code]){
                    success(me.kmsObjCodeDict[code]);
                }
                else{
                    me.loadPipe(pipeCode, clientId).then(pipe=>{
                        return pipe.create("PlayerEndpoint" , { uri: srcUrl } );
                    }).then(end=>{
                        return me.registObj(end , code , clientId);
                    }).then(obj=>{
                        success(obj);
                    })
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    connectHubPort( srcId , tarId  ){
        var me = this;
        var res ={
            status:0
        }
        return new Promise((success, faild)=>{
            try{
                var arr = srcId.split("/");
                if( arr.length>2){
                    var hubId = arr[0] +"/" + arr[1];
                    var src = null;
                    var tar = null;
                    var hub = null;
                    if( me.kmsObjIdDict[srcId] ){
                        src = me.kmsObjIdDict[srcId];
                    }
                    if( me.kmsObjIdDict[tarId] ){
                        tar = me.kmsObjIdDict[tarId];
                    }
                    if( me.kmsObjIdDict[hubId] ){
                        hub = me.kmsObjIdDict[hubId];
                    }
                    if( src = null){
                        res.status = -1;
                        success(res);
                    }
                    else if( tar = null){
                        res.status = -2;
                        success(res);
                    }
                    else if( hub = null){
                        res.status = -3;
                        success(res);
                    }
                    else {
                        hub.connect( src , tar , function(erConn){
                            res.status = (!erConn || erConn==null)?1:0;
                            success(res);
                        })
                    }
                }
                else{
                    success(res);
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    connectHubPortByCode( srcCode , tarCode  ){
        var me = this;
        var res ={
            status:0
        }
        return new Promise((success, faild)=>{
            try{
                var src = null;
                var tar = null;
                var hub = null;
                if( me.kmsObjCodeDict[srcCode] ){
                    src = me.kmsObjCodeDict[srcId];
                }
                if( me.kmsObjCodeDict[tarCode] ){
                    tar = me.kmsObjCodeDict[tarCode];
                } 
                if( src = null){
                    res.status = -1;
                    success(res);
                }
                else if( tar = null){
                    res.status = -2;
                    success(res);
                } 
                else {
                    var arr = src.id.split("/");
                    var hubId = arr[0] + "/" + arr[1];
                    if( me.kmsObjIdDict[hubId]){
                        var hub = me.kmsObjIdDict[hubId];
                        hub.connect( src , tar , function(erConn){
                            res.status = (!erConn || erConn==null)?1:0;
                            success(res);
                        })
                    }
                    else{
                        res.status = -3;
                        success(res);
                    }
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    queryObjInfosByCode( code  ){
        var me = this;
        var res ={};
        try{
            var objs = Object.values( me.kmsObjIdDict ).filter(obj=>{
                return obj.info.code.indexOf(code)==0;
            });
            objs.forEach(obj=>{
                res[obj.info.code] = obj.info;
            });
        }
        catch(er){
            console.log(er);
            success();
        }
        return res;
    }
    queryObjInfosByKmsId( kmsId  ){
        var me = this;
        var res ={};
        try{
            var objs = Object.values( me.kmsObjIdDict ).filter(obj=>{
                return obj.id.indexOf(kmsId)==0;
            });
            objs.forEach(obj=>{
                res[obj.id] = obj.info;
            });
        }
        catch(er){
            console.log(er);
            success();
        }
        return res;
    } 

    /*  -------------------------- API -------------------------- */
    registMqMsg(msg){
        try{
            if( msg.msgId =="online"){
                var clientId = msg.msgBody.clientId;
                var code = msg.msgBody.kmsId;
                var code = msg.msgBody.code;
                me.registObjById(kmsId , code , client).then(()=>{
                    console.log('regist obj :' , code , kmsId , clientId);
                });
            }
            else if( msg.msgId =="offline"){
                var clientId = msg.msgBody.clientId;
                me.removeKmsObjsByClientId(clientId).then(res=>{
                    console.log('removeKmsObjsByClientId :' , res);
                });
            }
            else if( msg.msgId =="loadPipe"){
                var code = msg.msgBody.code;
                var clientId = msg.msgBody.clientId;
                me.loadPipe(code , clientId).then(res=>{
                    console.log('loadPipe :' , res);
                });
            }
            else if( msg.msgId =="loadDevice"){
                var pipeCode = msg.msgBody.pipeCode;
                var code = msg.msgBody.code;
                var srcUrl = msg.msgBody.srcUrl;
                var clientId = msg.msgBody.clientId;
                me.loadDevice(pipeCode, code ,srcUrl , clientId).then(res=>{
                    console.log('loadDevice :' , res);
                });
            }
            else if( msg.msgId =="connectHubPort"){
                var srcId = msg.msgBody.srcId;
                var tarId = msg.msgBody.tarId;
                me.connectHubPort(srcId , tarId).then(res=>{
                    console.log('connectHubPort :' , res);
                })
            }
            else if( msg.msgId =="connectHubPortByCode"){
                var srcCode = msg.msgBody.srcCode;
                var tarCode = msg.msgBody.tarCode;
                me.connectHubPortByCode(srcCode , tarCode).then(res=>{
                    console.log('connectHubPort by code:' , res);
                })
            }
            else if( msg.msgId =="queryObjInfosByCode"){
                var code = msg.msgBody.code;
                me.queryObjInfosByCode(code).then(res=>{
                    console.log('queryObjInfosByCode :' , res);
                }) 
            }
            else if( msg.msgId =="queryObjInfosByKmsId"){
                var kmsId = msg.msgBody.kmsId;
                me.queryObjInfosByKmsId(kmsId).then(res=>{
                    console.log('queryObjInfosByKmsId :' , res);
                }) 
            }
        }
        catch(er){
            console.log(er);
        }
    }
    regist2WebSvr(webSvr){
        var me = this;
        me.db.apps[me.config.db.dbKey] = me.config.db.dbInfo;
        if( webSvr && webSvr!=null){
            var respJson = function(result , response){
                try{
                    response.send(JSON.stringify(result));
                }
                catch(eer){
                    console.log(eer);
                }
            }
            webSvr.registRoute ( "common" , "kmsManager" , "getConfig" , function( result , request , response ){                
                try{ 
                    var config ={
                        kmsUrl: me.config.kms.kmsUrl ,
                        dbKey: me.config.db.dbKey ,
                        mq:{
                            url:"tcp://gmggf8g.mqtt.iot.bj.baidubce.com:1883",
                            uid:"gmggf8g/peer",
                            pwd:"a52bwKg22dCAuQzB",
                            appTopic:"/hhmsg/notify"
                        }
                    } 
                    result.data = config;
                    respJson(result, response);
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            }); 
            webSvr.registRoute ( "common" , "kmsManager" , "getObjByCode" , function( result , request , response ){                
                try{ 
                    var code = result.ps.code;
                    var res = {
                        status: 0
                    }
                    if( me.kmsObjCodeDict[code]){
                        res.status = 1;
                        res.objInfo = me.kmsObjCodeDict[code].info;
                    }   
                    result.data = res.info;
                    respJson(result, response);
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            }); 
            webSvr.registRoute ( "common" , "kmsManager" , "loadPipe" , function( result , request , response ){                
                try{ 
                    var code = result.ps.code;
                    var clientId = result.ps.clientId;
                    me.loadPipe( code , clientId).then(res=>{       
                        result.data = res.info;
                        respJson(result, response);
                    })
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            });  
            webSvr.registRoute ( "common" , "kmsManager" , "loadDevice" , function( result , request , response ){                
                try{ 
                    var pipeCode = result.ps.pipeCode;
                    var code = result.ps.code;
                    var srcUrl = result.ps.srcUrl;
                    var clientId = result.ps.clientId;
                    me.loadDevice( pipeCode, code ,src , clientId).then(res=>{       
                        result.data = res.info;
                        respJson(result, response);
                    })
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            });  
            webSvr.registRoute ( "common" , "kmsManager" , "connectHubPort" , function( result , request , response ){                
                try{ 
                    var srcId = result.ps.srcId;
                    var tarId = result.ps.tarId;
                    me.connectHubPort(srcId , tarId).then(res=>{       
                        result.data = res;
                        respJson(result, response);
                    })
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            });  
            webSvr.registRoute ( "common" , "kmsManager" , "connectHubPortByCode" , function( result , request , response ){                
                try{ 
                    var srcCode = result.ps.srcCode;
                    var tarCode = result.ps.tarCode;
                    me.connectHubPortByCode(srcCode , tarCode).then(res=>{       
                        result.data = res;
                        respJson(result, response);
                    })
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            });  
            webSvr.registRoute ( "common" , "kmsManager" , "queryObjInfosByCode" , function( result , request , response ){                
                try{ 
                    var code = result.ps.code;
                    me.queryObjInfosByCode(code).then(res=>{       
                        result.data = res;
                        respJson(result, response);
                    })
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            });  
            webSvr.registRoute ( "common" , "kmsManager" , "queryObjInfosByKmsId" , function( result , request , response ){                
                try{ 
                    var kmsId = result.ps.kmsId;
                    me.queryObjInfosByKmsId(kmsId).then(res=>{       
                        result.data = res;
                        respJson(result, response);
                    })
                }
                catch(err){
                    console.log(err);
                    respJson(result, response);
                }
            });  
        }
    }
}